/**
 * @addtogroup FXGE
 * @{
 */

/**
 * @file
 * @brief Foxit font manager.
 */
#ifndef _FX_FONTMGR_H_
#define _FX_FONTMGR_H_

#ifndef _FX_FONT_H_
#include "../fxge/fx_font.h"
#endif

class CPDF_Font;
class CPDF_Document;
class CPDF_FontEncoding;
/**
 * @name Font related operation. 
 */
/*@{*/
#define FXWORD_SWAP_ENDIAN(i) ( ((FX_BYTE)((i) >> 8)) | ((FX_BYTE)(i) << 8) )

#if _FX_ENDIAN_ == _FX_BIG_ENDIAN_
#define FXWORD_FROM_LSBFIRST(i) FXWORD_SWAP_ENDIAN(i)
#define FXWORD_FROM_MSBFIRST(i) (i)
#else
#define FXWORD_FROM_LSBFIRST(i) (i)
#define FXWORD_FROM_MSBFIRST(i) FXWORD_SWAP_ENDIAN(i)
#endif

/** @brief Flags used for whether the font can be embedded or other operations to be executed. */
#define FXFM_EMBED_FORBIDDEN		0x0002	/**< Must not be modified, embedded or exchanged in any manner. */
#define FXFM_EMBED_PREVIEW_PRINT	0x0004	/**< May be embedded "read-only" for preview or print. */
#define FXFM_EMBED_EDIT				0x0008	/**< May be embedded "read-write". */
#define FXFM_EMBED_ALL				0x0000	/**< May be embedded and permanently installed on remote system except for original purchaser. */
#define FXFM_CAN_EMBED(flag)		(!((flag) & FXFM_EMBED_FORBIDDEN)) 

/** @brief Glyph Bitmap types. */
typedef enum
{
	FXFM_GLYPH_BITMAP_MONO,
	FXFM_GLYPH_BITMAP_BYTEMASK,
	FXFM_GLYPH_BITMAP_CLEARTYPE
} FM_GLYPH_BitmapType;

#define FXFM_RENDER_NORMAL			1
#define FXFM_RENDER_MONO			2
#define FXFM_RENDER_LCD				3
#define FXFM_RENDER_LCD_V			4

/** @brief Font format and type */  
#define FXFM_FONT_INVALID			-1	/**< Invalid font type. */                      
#define FXFM_NORMAL_TRUETYPE		0	/**< TrueType normal font type. */ 
#define FXFM_NORMAL_TYPE1			1	/**< Type 1 normal font type. */
#define FXFM_NORMAL_BDF				2	/**< BDF normal font type.*/
#define FXFM_NORMAL_PCF				3	/**< PCF normal font type.*/
#define FXFM_NORMAL_TYPE42			4	/**< Type 42 normal font type.*/
#define FXFM_NORMAL_CIDTYPE1		5	/**< CID Type 1 normal font type.*/
#define FXFM_NORMAL_CFF				6	/**< CFF normal font type. */
#define FXFM_NORMAL_PFR				7	/**< PFR normal font type. */
#define FXFM_NORMAL_WINFNT			8	/**< Windows FNT normal font type. */

/**
 * @brief Extension font interface.
 *
 * Provide more font operation than CFX_Font.
 */
class IFX_FontEx : public CFX_Object
{
public:
	/** Called when to release everything. */
	virtual void		Release() = 0;

	/** 
	 * Get context for basic font operating. 
	 * 
	 * @return Pointer to CFX_Font
	 */
	virtual CFX_Font*	GetFont() const = 0;

	/**
	 * Indicates font embedding licensing rights for the font.
	 * Embeddable fonts may be stored in a document.
	 * When a document with embedded fonts is opened on a system that does 
	 * not have the font installed (the remote system), the embedded font may be loaded for
	 * temporary (and in some cases, permanent) use on that system by an embedding-aware
	 * application. Embedding licensing rights are granted by the vendor of the font. 
	 *
	 * @return The flag describes in FXFM_EMBED_XXX
	 */
	virtual FX_WORD		GetEmbedLicence() const = 0;

	/** 
	 * Get the format and type of the face. 
	 * 
	 * @return Font type describes in FXFM_NORMAL_XXX
	 */
	virtual int			GetFontType() const = 0;

	/** 
	 * Get a face's face index among the whole font. 
	 */
	virtual int			GetFaceIndex() const = 0;

	/** 
	 * Get the count of glyph of the face. 
	 */
	virtual FX_DWORD	GetGlyphCount() const = 0;

	/**
	 * Get glyph bitmap. Implementation of this interface is required.
	 * If the basic font use the MM font as substitute font, user need to adjust MM parameters.
	 *
	 * @param[in] glyph_index	    The glyph_index of the character.
	 * @param[in] pMatrix			The character matrix. Only a,b,c,d used.
	 * 								If the substitute flag indicates glyph transformation supported, then this can be
	 * 								any kind of matrix. Otherwise, only a,d have value, and a == d.
	 * @param[in,out] type			Bitmap type requested.
	 *								On return, this is the type actually offered by the provider.
	 * @param[out] left				Offset from the char origin to left side of the bitmap.
	 *								Negative is to the left, positive is to the right.
	 * @param[out] top				offset from the char origin to top side of the bitmap.
	 *								Negative is downward, positive is upward.
	 * @param[out] pixel_width		Width (in pixels) of the result bitmap.
	 * @param[out] pixel_height		Height (in pixels) of the result bitmap.
	 * @param[out] buffer			Result buffer. Must be allocated using FX_Alloc.
	 *								The buffer will be freed by FPDFAPI.
	 * @param[out] stride			Number of bytes per line in the result bitmap.
	 * @return Return TRUE for success, FALSE for failure (or empty glyph).
	 */
	virtual FX_BOOL		GetGlyphBitmap(FX_DWORD dwGlyphIndex, const CFX_AffineMatrix* pMatrix, 
									FM_GLYPH_BitmapType& type, int& left, int& top,	
									int& pixel_width, int& pixel_height, FX_LPBYTE& buffer,	
									int& stride) const = 0;

	/** 
	 * Attach AFM control to font. Applicable to Type1 font only. 
	 * 
	 * @param[in] pFile				Pointer to file/stream interface.
	 * @return TRUE means success, otherwise failure.
	 */
	virtual FX_BOOL		AttatchAFM(IFX_FileRead* pFile) = 0;

	/** 
	 * Attach AFM control to font. Applicable to Type1 font only. 
	 * 
	 * @param[in] pData				Pointer to memory-based stream.
	 * @param[in] dwSize			Stream size.
	 * @return TRUE means success, otherwise failure.
	 */
	virtual FX_BOOL		AttatchAFM(FX_LPCBYTE pData, FX_DWORD dwSize) = 0;
};

/**
 * @brief Get font face count, Only TTC may have more than 1 face.
 *
 * @param[in] pFile				Pointer to font file/stream interface.
 * @return Face count
 */ 
int					FX_GetFontFaceCount(IFX_FileRead* pFile);
/**
 * @brief Get font face count, Only TTC may have more than 1 face.
 *
 * @param[in] pFontData			Pointer to memory-based font stream.
 * @param[in] dwFontSize		Font stream size.
 * @return Face count
 */ 
int					FX_GetFontFaceCount(FX_LPCBYTE pFontData, FX_DWORD dwFontSize);

/** 
 * Create an extension font interface.
 * @param[in] pFile				Pointer to font file/stream interface.
 * @param[in] nFaceIndex		The zero-based face index[0, face_count)
 * @return Pointer to an extension font interface.
 */
IFX_FontEx*			FX_CreateFontEx(IFX_FileRead* pFile, int nFaceIndex = 0);
/** 
 * Create an extension font interface. 
 * @param[in] pData				Pointer to memory-based font stream.
 * @param[in] dwSize			Font stream size.
 * @param[in] nFaceIndex		The zero-based face index[0, face_count)
 * @return Pointer to an extension font interface.
 */
IFX_FontEx*			FX_CreateFontEx(FX_LPCBYTE pData, FX_DWORD dwSize, int nFaceIndex = 0);
/** 
 * Create an extension font interface. 
 * @param[in] pFont				Pointer to basic font context.
 * @return Pointer to an extension font interface.
 */
IFX_FontEx*			FX_CreateFontEx(CFX_Font* pFont, FX_BOOL bTakeover = FALSE);
/*@}*/

/** 
 * @name Font encoding related operation 
 */
/*@{*/

/**
 * Create extension font encoding interface
 * 
 * @param[in] pFontEx				Pointer to the extension font context.
 * @param[in] nEncodingID			The encoding id to select the char map. Describes in FXFM_ENCODING_XXX.
 * @return NULL for failure(such as, the nEncodingID can't be found).
 */
IFX_FontEncodingEx* FX_CreateFontEncodingEx(IFX_FontEx* pFontEx, FX_DWORD nEncodingID = FXFM_ENCODING_NONE);
/*@}*/

/**
 * @name Font subset related operation
 */
/*@{*/

/** @brief Truetype font subset layout type.  */
#define FXFM_TT_SUBSET_LAYOUT_H		0x00000001
#define FXFM_TT_SUBSET_LAYOUT_V		0x00000002
#define FXFM_TT_SUBSET_LAYOUT_B		0x00000003

/** @brief Type1 font subset output format. */
typedef enum
{
	FXFM_T1_OUTPUT_PFB,
	FXFM_T1_OUTPUT_PFA,
	FXFM_T1_OUTPUT_RAW
} FXFM_TYPE1_OutputType;

/** @brief OpenType font subset output format. */
typedef enum
{
	FXFM_OT_OUTPUT_CFF, 
	FXFM_OT_OUTPUT_OTF
} FXFM_OPENTYPE_OutputType;

/** @brief Font subset generation interface. */
class IFX_FontSubset : public CFX_Object
{
public:
	/** Release internal context. Called when to release everything. */
	virtual void			Release() = 0;

	/** 
	 * Add a glyph which supplied by the based font.
	 * 
	 * @param[in] dwGlyphIndex		The zero-based glyph index of based font.
	 * @return The glyph index of the subset to be generated, or 0 for failure.
	 */
	virtual FX_DWORD		AddGlyph(FX_DWORD dwGlyphIndex) = 0;
	virtual FX_DWORD		AddGlyph(FX_DWORD dwGlyphIndex, FX_DWORD charcode) = 0;
	virtual void			ClearCache() = 0;

	/** 
	 * Generate subset buffer.
	 *
	 * @param[in, out] out			It received the new subset font stream.
	 * return TRUE means success, otherwise failure.
	 */
	virtual FX_BOOL			GenerateSubset(CFX_BinaryBuf& out) = 0;
	
	/** 
	 * Features enabled only for truetype fonts.
     * You can make your choice to generate truetype data.
	 * It must be called before GenerateSubset being called,
	 * The default enabled layout is FX_TRUETYPE_SUBSET_LAYOUT_HORIZONAL, 
	 * if you won't change, don't call this function.
	 *
	 * @param[in] layout			Describes in FX_TRUETYPE_SUBSET_LAYOUT_XXX
	 */
	virtual void			SetLayout(FX_DWORD layout) {}
	
	/**
	 * Features enabled only for type1 fonts.
	 * You can make your choice to generate type1 data.
	 * It must be called before GenerateSubset being called,
	 * the default format is FX_TYPE1_OUTPUT_PFB, if you won't change, don't call
	 * this function.
	 *
	 * @param[in] type				Describes in enum FXFM_TYPE1_OutputType.
	 */
	virtual void			SetOutputType(FXFM_TYPE1_OutputType type = FXFM_T1_OUTPUT_PFB) {}
	
	/**
	 * Features enabled only for type1 fonts.
	 * 
	 * @param[out] dwLength1		It received the length for clear-text portion.
	 * @param[out] dwLength2		It received the length for encrypted portion.
	 * @param[out] dwLength3		It received the length for fixed-content portion.
	 */
	virtual void			GetLengths(FX_DWORD &dwLength1, FX_DWORD &dwLength2, FX_DWORD &dwLength3) {}

	/** 
	 * Features enabled only for cff fonts. Set the Subset file format.
	 * You can make your choice to generate cff data.
	 * It must be called before GenerateSubset being called,
	 * the default format is FXFM_OT_OUTPUT_CFF, if you won't change, don't call
	 * this function.
	 * 
	 * @param[in] type				Describes in enum FXFM_OPENTYPE_OutputType
	 */
	virtual void			SetSubsetType(FXFM_OPENTYPE_OutputType type = FXFM_OT_OUTPUT_CFF) {}
};

/** 
 * Create a font subset.
 *
 * @param[in] pFontEx			Pointer to extension font context.
 * @return Pointer to an font subset interface.
 */
IFX_FontSubset*		FX_CreateFontSubset(IFX_FontEx *pFontEx);
/** 
 * Create a font subset.
 *
 * @param[in] pFont				Pointer to basic font context.
 * @return Pointer to an font subset interface.
 */
IFX_FontSubset*		FX_CreateFontSubset(CFX_Font* pFont);
/*@}*/

/**
 * @name Font recognizer related operation
 */
/*@{*/

/** @brief IFX_FontRecognizer interface. */
class IFX_FontRecognizer : public CFX_Object
{
public:
	/**
	 * Only used for some embedded fonts, when losing it's encoding and to unicode informations.
	 * need to compare 'nGlyphIndex' in "pInputFontEx" font to glyphs in 'pOutputFontEx',
	 * then return the matched glyph index in 'pOutputFontEx'.
	 *
	 * @param[in] pSrcFontEx			Pointer to the source font interface.
	 * @param[in] dwSrcGlyphIndex		The source font glyph index.
	 * @param[in] pDestFontEx			Pointer to the destination font interface to be recognized.
	 * @return The glyph index of the destination font, -1 for failure.
	 */
	virtual FX_DWORD		RecognizeGlyph(IFX_FontEx* pSrcFontEx, FX_DWORD dwSrcGlyphIndex, IFX_FontEx* pDestFontEx) = 0;
};

/**
 * @brief Create a font glyph recognizer interface.
 */
IFX_FontRecognizer*	FX_CreateFontRecognizer();
/*@}*/

/**
 * @name More font related operation
 */
/*@{*/

/**
 * @brief Convert the CFF file to OTF.
 * If the Font face has no charmaps, then add 2 charmaps to OTF 'cmap' table. 
 * One is Format 4, for the Unicode Encoding, the other one is Format 6, 
 * for the symbol Encoding.
 *
 * @param[in] pFile					Pointer to the source CFF file/stream interface.
 * @param[out] out					The converted OTF file data.
 */
FX_BOOL				ConvertCFF2OTF(IFX_FileRead* pFile, CFX_BinaryBuf& out);
/**
 * @brief Convert the CFF file to OTF.
 * If the Font face has no charmaps, then add 2 charmaps to OTF 'cmap' table. 
 * One is Format 4, for the Unicode Encoding, the other one is Format 6, 
 * for the symbol Encoding.
 *
 * @param[in] pFontData				Pointer to memory-based cff font stream.
 * @param[in] dwFontSize			The source CFF font stream size.
 * @param[out] out					The converted OTF file data.
 */
FX_BOOL				ConvertCFF2OTF(FX_LPCBYTE pFontData, FX_DWORD dwFontSize, CFX_BinaryBuf& out);
/**
 * @brief Convert the CFF file to OTF.
 * If the Font face has no charmaps, then add 2 charmaps to OTF 'cmap' table. 
 * One is Format 4, for the Unicode Encoding, the other one is Format 6, 
 * for the symbol Encoding.
 *
 * @param[in] pFontEx				Pointer to the extension font interface, this font must be cff.
 * @param[out] out					The converted OTF file data.
 */
FX_BOOL				ConvertCFF2OTF(IFX_FontEx *pFontEx, CFX_BinaryBuf& out);
/**
 * @brief Convert the CFF file to OTF.
 * If the Font face has no charmaps, then add 2 charmaps to OTF 'cmap' table. 
 * One is Format 4, for the Unicode Encoding, the other one is Format 6, 
 * for the symbol Encoding.
 *
 * @param[in] pFont					Pointer to source font, this font must be cff.
 * @param[out] out					The converted OTF file data.
 * @return
 */
FX_BOOL				ConvertCFF2OTF(CFX_Font* pFont, CFX_BinaryBuf& out);

/** @brief Dump the font info to the logfile. 
 * @param[in] fontfile				The font file path.
 * @param[in] logfile				The output log file path.
*/
FX_BOOL	DumpFont(FX_LPCSTR fontfile, FX_LPCSTR logfile);
/*@}*/

FX_DEFINEHANDLE(FXFM_FONT);

class CFX_FontConvertMgr : public CFX_Object
{
public:
	~CFX_FontConvertMgr();

	FX_BOOL				Init();

	/**
	* Support font format:
	*	1. PFB font
	*	2. ttf font
	*	3. otf font
	*/
	FXFM_FONT			LoadFont(IFX_FileRead* pFileRead);
	void				FreeFont(FXFM_FONT font);

	void				AddGlyph(FXFM_FONT font, int glyph_index, FX_DWORD unicode);
	void				GenerateCmap(FXFM_FONT font);

	FX_BOOL				WriteOTFFont(FXFM_FONT font, CFX_BinaryBuf& out);
	FX_BOOL				WriteWOFFFont(FXFM_FONT font, CFX_BinaryBuf& out);

};

//*****************************************************************************
//* Font
//*****************************************************************************
class IFX_FMFont : public CFX_Object
{
public:
	virtual void			Release() = 0;

	virtual IFX_FMFont*		Retain() = 0;

	virtual CFX_Font*		GetFont() = 0;

	virtual FX_DWORD		CharCodeFromUnicode(FX_WCHAR wUnicode) = 0;
	virtual FX_DWORD		GlyphFromCharCode(FX_DWORD charcode) = 0;

	virtual FX_DWORD		CharCodeFromGlyphIndex(FX_DWORD dwGlyphIndex) = 0;
	virtual CFX_WideString	UnicodeFromCharCode(FX_DWORD charcode) const = 0;

	virtual int				GetCharWidthF(FX_DWORD charcode, int level = 0) = 0;

	virtual void			AddUnicodes(FX_DWORD* pUnicodes, FX_DWORD size) = 0;

	virtual CPDF_Font*		GetPDFFont() = 0;
	virtual FX_BOOL			IsEmbedded() = 0;

	virtual FX_DWORD		GetEmbedLicence() = 0;
};

//*****************************************************************************
//* Font match
//*****************************************************************************
typedef struct _FXFM_FONTSIGNATURE : public CFX_Object{
	FX_DWORD			fsUsb[4];
	FX_DWORD			fsCsb[2];
}FXFM_FONTSIGNATURE;

typedef struct _FXFM_FONTDESCRIPTOR : public CFX_Object{
	_FXFM_FONTDESCRIPTOR(){}
	_FXFM_FONTDESCRIPTOR(const _FXFM_FONTDESCRIPTOR& src)
	{
		uCharSet = src.uCharSet;
		dwFontStyles = src.dwFontStyles;
		FXSYS_memcpy32(bsFontFace, src.bsFontFace, sizeof(bsFontFace));
		FXSYS_memcpy32(&FontSignature, &src.FontSignature, sizeof(FXFM_FONTSIGNATURE));
	}

	FX_CHAR				bsFontFace[32];
	FX_DWORD			dwFontStyles;
	FX_WORD				uCharSet;
	FXFM_FONTSIGNATURE	FontSignature;
}FXFM_FONTDESCRIPTOR;
typedef CFX_ObjectArray<FXFM_FONTDESCRIPTOR>		CFX_FontDesArray;

typedef struct _FXFM_FONTMATCHPARAMS : public CFX_Object{
	FX_LPCSTR			pFamily;
	FX_DWORD			dwFontStyles;
	FX_DWORD			dwUSB;
	FX_WCHAR			wUnicode;
	FX_WORD				uCharset;
	FX_BOOL				bMatchStyles;
}FXFM_FONTMATCHPARAMS;

typedef FXFM_FONTDESCRIPTOR*	(*FXFM_LPMatchFont)(const FXFM_FONTMATCHPARAMS* pParams, const CFX_FontDesArray* fonts, FX_LPVOID pUserData);
typedef FX_BOOL					(*FXFM_LPNeedToEmbed)(FX_LPCSTR family, FX_WORD charset, FX_LPVOID pUserData);
typedef CPDF_Font*				(*FXFM_LPGetStandardFont)(CPDF_Document* pDocument, FX_LPCSTR font, FX_LPVOID pUserData);

FXFM_LPMatchFont	FXFM_GetDefFontMatchor();
FXFM_LPNeedToEmbed	FXFM_GetDefEmbedProc();
void				FXFM_EnumFonts(CFX_FontDesArray& fonts, FX_LPCSTR pFamily = NULL);

inline FX_BOOL operator == (const FXFM_FONTDESCRIPTOR &left, const FXFM_FONTDESCRIPTOR &right)
{
	return left.uCharSet == right.uCharSet
		&& left.dwFontStyles == right.dwFontStyles
		&& FXSYS_strcmp((FX_LPCSTR)left.bsFontFace, (FX_LPCSTR)right.bsFontFace) == 0
		&& FXSYS_memcmp32(&left.FontSignature, &right.FontSignature, sizeof(FXFM_FONTSIGNATURE)) == 0;
}

class CFX_FMContextParam : public CFX_Object
{
public:
	CFX_FMContextParam()
		: m_pUserData(NULL)
		, m_pDocument(NULL)
		, m_pMatch(NULL)
		, m_pEmbProc(NULL)
		, m_pStandardFontProc(NULL)
	{

	}

	FX_LPVOID				m_pUserData;
	CPDF_Document*			m_pDocument;
	FXFM_LPMatchFont		m_pMatch;
	FXFM_LPNeedToEmbed		m_pEmbProc;
	FXFM_LPGetStandardFont	m_pStandardFontProc;
};

class IFX_FontMatch : public CFX_Object
{
public:
	virtual ~IFX_FontMatch(){}

	virtual void		SetDefaultFont(CFX_Font* pFont) = 0;
	virtual void		SetDefaultFont(FX_BSTR bsFamily) = 0;

	virtual void*		CreateContext(CFX_FMContextParam* pParam) = 0;
	virtual void		DestroyContext(void* context) = 0;

  	virtual IFX_FMFont*	LoadFont(void* context, FX_BSTR family, FX_DWORD dwFontStyle,
  							int weight, int italic_angle, int Charset, FX_BOOL bVertical = FALSE) = 0;
	virtual IFX_FMFont*	LoadFont(void* context, CFX_Font* pFont, FX_BOOL bTakeover = FALSE) = 0;
	virtual IFX_FMFont*	LoadFont(void* context, CPDF_Font* pFont, FX_BOOL bNeedToEmbedd = FALSE) = 0;

	virtual IFX_FMFont*	GetFontByUnicode(void* context, FX_WCHAR wUnicode, FX_DWORD dwFontStyle, FX_BOOL bVertical = FALSE) = 0;
	virtual void		ClearFontCache(void* context) = 0;
};

IFX_FontMatch*		FX_CreateFontMatch();

//*****************************************************************************
//* Font Edit
//*****************************************************************************
typedef CFX_ArrayTemplate<FX_WCHAR>	CFX_WCHARArray;
class IFXFM_FontEdit
{
public:
	virtual void		Release() = 0;

	virtual FX_BOOL		SetFont(IFX_FMFont* pFont) = 0;
	virtual void		ClearCache() = 0;

	virtual void		SetVerticalLayout(FX_BOOL bEnable) = 0;
	virtual FX_BOOL		GlyphFromUnicode(const CFX_WCHARArray& wcUnicodes, CFX_DWordArray& dwGlyphs, CFX_Int32Array& nGlyphCounts) = 0;
};
IFXFM_FontEdit*		FXFM_CreateFontEdit();

#endif

